package com.gitee.wsl.ext.string

import arrow.core.fold
import com.gitee.wsl.text.format.format

private fun String.replaceWithVariable(name: String, value: String): String {
    return replace("{{$name}}", value)
}

fun String.withReplacedArgs(args: Map<String, String>): String {
    return args.fold(this) { acc, entry ->
        acc.replaceWithVariable(entry.key, entry.value)
    }
}

/**
 * 获得set或get或is方法对应的标准属性名<br></br>
 * 例如：setName 返回 name
 *
 * <pre>
 * getName =》name
 * setName =》name
 * isName  =》name
</pre> *
 *
 * @param getOrSetMethodName Get或Set方法名
 * @return 如果是set或get方法名，返回field， 否则null
 */
fun getGeneralField(getOrSetMethodName: CharSequence): String? {
    val getOrSetMethodNameStr = getOrSetMethodName.toString()
    if (getOrSetMethodNameStr.startsWith("get") || getOrSetMethodNameStr.startsWith("set")) {
        return getOrSetMethodName.removePreAndLowerFirst( 3)
    } else if (getOrSetMethodNameStr.startsWith("is")) {
        return getOrSetMethodName.removePreAndLowerFirst(2)
    }
    return null
}

/**
 * 生成set方法名<br></br>
 * 例如：name 返回 setName
 *
 * @param fieldName 属性名
 * @return setXxx
 */
fun genSetter(fieldName: CharSequence): String {
    return fieldName.upperFirstAndAddPre( "set")
}

/**
 * 生成get方法名
 *
 * @param fieldName 属性名
 * @return getXxx
 */
fun genGetter(fieldName: CharSequence): String {
    return fieldName.upperFirstAndAddPre( "get")
}

/**
 * 去掉首部指定长度的字符串并将剩余字符串首字母小写<br></br>
 * 例如：str=setName, preLength=3 =》 return name
 *
 * @param str       被处理的字符串
 * @param preLength 去掉的长度
 * @return 处理后的字符串，不符合规范返回null
 */
fun CharSequence.removePreAndLowerFirst( preLength: Int): String {
    val str=this
    if (str.length > preLength) {
        val first = str[preLength].lowercaseChar()
        if (str.length > preLength + 1) {
            return first.toString() + str.toString().substring(preLength + 1)
        }
        return first.toString()
    } else {
        return str.toString()
    }
}

/**
 * 原字符串首字母大写并在其首部添加指定字符串 例如：str=name, preString=get =》 return getName
 *
 * @param str       被处理的字符串
 * @param preString 添加的首部
 * @return 处理后的字符串
 */
fun CharSequence.upperFirstAndAddPre(preString: String): String {
    return preString + upperFirst()
}

/**
 * 大写首字母<br></br>
 * 例如：str = name, return Name
 *
 * @param str 字符串
 * @return 字符串
 */
fun CharSequence.upperFirst(): String {
    if (isNotEmpty()) {
        val firstChar = this[0]
        if (firstChar.isLowerCase()) {
            return firstChar.uppercaseChar() + substring(1)
        }
    }
    return toString()
}

fun nextName(varName: String?): String {
    if (varName == null || varName.isEmpty()) return "1"

    val c = varName.get(varName.length - 1)
    if (c == ')') {
        val pos = varName.lastIndexOf('(')
        if (pos >= 0) {
            val seq = varName.substring(pos + 1, varName.length - 1)
//            if (seq.isInt()) {
//                val intValue = seq.toInt( 10)
//                return varName.substring(0, pos + 1) + (intValue + 1) + ")"
//            }
            seq.toIntOrNull()?.let {intValue->
                return varName.substring(0, pos + 1) + (intValue + 1) + ")"
            }
        }
    } else if (c == ']') {
        val pos = varName.lastIndexOf('[')
        if (pos >= 0) {
            val seq = varName.substring(pos + 1, varName.length - 1)
//            if (seq.isInt()) {
//                val intValue = seq.toInt( 10)
//                return varName.substring(0, pos + 1) + (intValue + 1) + "]"
//            }
            seq.toIntOrNull()?.let { intValue ->
                return varName.substring(0, pos + 1) + (intValue + 1) + "]"
            }
        }
    }

    if (c.isDigit()) {
        if (c < '9') {
            val c2 = (c.code + 1).toChar()
            return varName.substring(0, varName.length - 1) + c2
        } else {
            val pos: Int = _searchNotDigit(varName)
            if (pos < 0) {
                // 全部都是9
                return "1" + "0".repeat( varName.length)
            }
            val num: Int = (varName.substring(pos + 1)).toInt(10) + 1
            val size = varName.length - pos
            return varName.substring(0, pos + 1) + String.format("%0" + size + "d", num)
        }
    }
    return varName + "1"
}

private fun _searchNotDigit(varName: String): Int {
    for (i in varName.length - 1 downTo 0) {
        val c = varName.get(i)
        if (!c.isDigit()) return i

        if (c < '9') return i - 1
    }
    return -1
}